-- Baza danych obiektow turystycznych 
 
BEGIN; 
 
------------------------------------ 
-- 0. OGOLNE: [OK] 
 
-- (A) usuwanie istniejacych relacji: 
 
DROP TABLE IF EXISTS kategorie CASCADE; 
DROP SEQUENCE IF EXISTS id_dla_kat; 
DROP TABLE IF EXISTS obiekty CASCADE; 
DROP SEQUENCE IF EXISTS id_dla_ob; 
DROP TABLE IF EXISTS zdjecia CASCADE; 
DROP TABLE IF EXISTS okresy_otwarcia CASCADE; 
DROP TABLE IF EXISTS przewodnicy CASCADE; 
DROP SEQUENCE IF EXISTS id_dla_przew; 
DROP TABLE IF EXISTS przewodnicyobiekty CASCADE; 
DROP TABLE IF EXISTS jezyki CASCADE; 
DROP TABLE IF EXISTS przewodnicyjezyki CASCADE; 
DROP TABLE IF EXISTS wejscia CASCADE; 
DROP SEQUENCE IF EXISTS id_dla_wej; 
DROP TABLE IF EXISTS uzytkownicy CASCADE; 
DROP TABLE IF EXISTS oceny CASCADE; 
DROP TABLE IF EXISTS oceny CASCADE; 
DROP TABLE IF EXISTS typy_biletow CASCADE; 
DROP SEQUENCE IF EXISTS id_dla_typu; 
DROP TABLE IF EXISTS wejsciarodzaje CASCADE; 
DROP TABLE IF EXISTS bilety CASCADE; 
DROP SEQUENCE IF EXISTS id_dla_bil; 
 
-- (B) funkcja normalizujaca czas (zaookraglenie do najblizszych 5minut bez patrzenia na sekundy): 
CREATE OR REPLACE FUNCTION normalizuj_czas(time) RETURNS time AS $normalizuj_czas$                  
BEGIN 
    RETURN date_trunc('hour', $1) + INTERVAL '5 min' * ROUND(date_part('minute', $1) / 5.0); 
END; 
$normalizuj_czas$ LANGUAGE plpgsql;     
 
------------------------------------ 
-- 1. KATEGORIE: [OK] 
 
-- (A) relacja: 
CREATE TABLE kategorie ( 
    nazwa varchar NOT NULL CONSTRAINT nazwa_nie_pust CHECK(nazwa != ''), 
    id_kat integer NOT NULL PRIMARY KEY -- nadawane automatycznie / niezmienialne 
); 
 
-- (B) sekwencja dla id: 
CREATE SEQUENCE id_dla_kat START 1; 
 
-- (C) wyzwalacz do insert'a: 
CREATE OR REPLACE FUNCTION dodaj_kat() RETURNS trigger AS $dodaj_kat$                  
BEGIN          
    NEW.id_kat = nextval('id_dla_kat'); 
    RETURN NEW; 
END; 
$dodaj_kat$ LANGUAGE plpgsql; 
CREATE TRIGGER dodaj_kat BEFORE INSERT ON kategorie 
FOR EACH ROW EXECUTE PROCEDURE dodaj_kat(); 
 
-- (D) wyzwalacz do update'a: 
CREATE OR REPLACE FUNCTION modyf_kat() RETURNS trigger AS $modyf_kat$                  
BEGIN 
    NEW.id_kat = OLD.id_kat; 
    IF NEW = OLD THEN 
        RETURN NULL; 
    END IF;     
    RETURN NEW; 
END; 
$modyf_kat$ LANGUAGE plpgsql; 
CREATE TRIGGER modyf_kat BEFORE UPDATE ON kategorie 
FOR EACH ROW EXECUTE PROCEDURE modyf_kat(); 
 
------------------------------------ 
-- 2. OBIEKTY:[OK] 
 
-- (A) relacja: 
CREATE TABLE obiekty ( 
    id_kat integer NOT NULL REFERENCES kategorie(id_kat), 
    nazwa varchar NOT NULL CONSTRAINT nazwa_nie_pust CHECK(nazwa != ''), 
    pojemnosc integer NOT NULL CONSTRAINT pojemnosc_dodatn CHECK(pojemnosc > 0), 
    kraj varchar NOT NULL, 
    wojewodztwo varchar, 
    miasto varchar, 
    adres varchar, 
    opis_kr varchar, 
    opis_dl text, 
    id_ob integer NOT NULL PRIMARY KEY  -- nadawane automatycznie / niezmienialne 
); 
 
-- (B) sekwencja dla id: 
CREATE SEQUENCE id_dla_ob START 1; 
 
 
-- (C) wyzwalacz do insert'a: 
CREATE OR REPLACE FUNCTION dodaj_ob() RETURNS trigger AS $dodaj_ob$                  
BEGIN          
    NEW.id_ob = nextval('id_dla_ob'); 
    RETURN NEW; 
END; 
$dodaj_ob$ LANGUAGE plpgsql; 
CREATE TRIGGER dodaj_ob BEFORE INSERT ON obiekty 
FOR EACH ROW EXECUTE PROCEDURE dodaj_ob(); 
 
-- (D) wyzwalacz do update'a: 
CREATE OR REPLACE FUNCTION modyf_ob() RETURNS trigger AS $modyf_ob$ 
BEGIN 
    NEW.id_ob = OLD.id_ob; 
    IF NEW = OLD THEN 
        RETURN NULL; 
    END IF;     
    RETURN NEW; 
END; 
$modyf_ob$ LANGUAGE plpgsql; 
CREATE TRIGGER modyf_ob BEFORE UPDATE ON obiekty 
FOR EACH ROW EXECUTE PROCEDURE modyf_ob(); 
 
------------------------------------ 
-- 3. ZDJECIA: [OK] 
 
-- (A) relacja: 
CREATE TABLE zdjecia ( 
    id_ob integer NOT NULL REFERENCES obiekty(id_ob), 
    url varchar NOT NULL PRIMARY KEY, 
    podpis varchar, 
    data date DEFAULT now() 
); 
 
------------------------------------ 
-- 4. OKRESY_OTWARCIA: [OK] 
 
-- (A) funkcja sprawdzajaca czy okresy otwarcia nie zachodza na siebie 
CREATE OR REPLACE FUNCTION czas_bez_zachodzenia(integer,integer,time,time) RETURNS boolean AS $czas_bez_zachodzenia$                      
DECLARE 
    V_liczba integer; 
BEGIN 
    SELECT count(*) FROM okresy_otwarcia WHERE id_ob = $1 AND dzien_tyg = $2 AND (godzina_od, godzina_do) overlaps ($3,$4) INTO V_liczba; 
    IF V_liczba > 0 THEN  
        RETURN FALSE; 
    END IF; 
    SELECT count(*) FROM okresy_otwarcia WHERE id_ob = $1 AND dzien_tyg = $2 AND ( godzina_od = $4 OR godzina_do = $3 ) INTO V_liczba; 
    IF V_liczba > 0 THEN 
        RETURN FALSE; 
    END IF; 
    RETURN TRUE; 
END; 
$czas_bez_zachodzenia$ LANGUAGE plpgsql; 
 
-- (B) relacja 
CREATE TABLE okresy_otwarcia ( 
    id_ob integer NOT NULL REFERENCES obiekty(id_ob), 
    dzien_tyg integer NOT NULL CONSTRAINT dzien_tyg_od_1_do_7 CHECK(dzien_tyg BETWEEN 1 AND 7), 
    godzina_od time NOT NULL, 
    godzina_do time NOT NULL, 
    PRIMARY KEY (id_ob,dzien_tyg,godzina_od), 
    CONSTRAINT godziny_chronologicznie CHECK(godzina_od < godzina_do), 
    CONSTRAINT czas_bez_zachodzenia CHECK(czas_bez_zachodzenia(id_ob,dzien_tyg,godzina_od,godzina_do)) 
); 
 
-- (C) wyzwalacz do inserta'a: 
CREATE OR REPLACE FUNCTION dodaj_ok_otw() RETURNS trigger AS $dodaj_ok_otw$                  
BEGIN 
    NEW.godzina_od = normalizuj_czas(NEW.godzina_od); 
    NEW.godzina_do = normalizuj_czas(NEW.godzina_do); 
    RETURN NEW; 
END; 
$dodaj_ok_otw$ LANGUAGE plpgsql; 
CREATE TRIGGER dodaj_ok_otw BEFORE INSERT ON okresy_otwarcia 
FOR EACH ROW EXECUTE PROCEDURE dodaj_ok_otw(); 
 
------------------------------------ 
-- 5. PRZEWODNICY: [OK] 
 
-- (A) relacja: 
CREATE TABLE przewodnicy ( 
    imie varchar NOT NULL CONSTRAINT imie_not_empty CHECK(imie != ''), 
    nazwisko varchar NOT NULL CONSTRAINT nazwisko_not_empty CHECK(nazwisko != ''), 
    id_przew integer NOT NULL PRIMARY KEY 
); 
 
-- (B) sekwencja dla id: 
CREATE SEQUENCE id_dla_przew START 1; 
 
-- (C) wyzwalacz do insert'a: 
CREATE OR REPLACE FUNCTION dodaj_przew() RETURNS trigger AS $dodaj_przew$                  
BEGIN          
    NEW.id_przew = nextval('id_dla_przew'); 
    RETURN NEW; 
END; 
$dodaj_przew$ LANGUAGE plpgsql; 
CREATE TRIGGER dodaj_przew BEFORE INSERT ON przewodnicy 
FOR EACH ROW EXECUTE PROCEDURE dodaj_przew(); 
 
-- (D) wyzwalacz do update'a: 
CREATE OR REPLACE FUNCTION modyf_przew() RETURNS trigger AS $modyf_przew$                  
BEGIN 
    NEW.id_przew = OLD.id_przew; 
    IF NEW = OLD THEN 
        RETURN NULL; 
    END IF; 
    RETURN NEW; 
END; 
$modyf_przew$ LANGUAGE plpgsql; 
CREATE TRIGGER modyf_przew BEFORE UPDATE ON przewodnicy 
FOR EACH ROW EXECUTE PROCEDURE modyf_przew(); 
 
------------------------------------ 
-- 6. PRZEWODNICYOBIEKTY: [OK] 
 
-- (A) relacja: 
CREATE TABLE przewodnicyobiekty ( 
    id_przew integer NOT NULL REFERENCES przewodnicy(id_przew), 
    id_ob integer NOT NULL REFERENCES obiekty(id_ob), 
    PRIMARY KEY(id_ob,id_przew) 
); 
 
------------------------------------ 
-- 7. JEZYKI: [OK] 
 
-- (A) relacja: 
CREATE TABLE jezyki ( 
    nazwa_jez varchar NOT NULL CONSTRAINT nazwa_jez_nie_pust CHECK(nazwa_jez != '') PRIMARY KEY 
); 
 
------------------------------------ 
-- 8. PRZEWODNICYJEZYKI: [OK] 
 
-- (A) relacja: 
CREATE TABLE przewodnicyjezyki ( 
    id_przew integer NOT NULL REFERENCES przewodnicy(id_przew), 
    nazwa_jez varchar NOT NULL REFERENCES jezyki(nazwa_jez) 
); 
 
------------------------------------ 
-- 9. WEJSCIA: [OK] 
 
-- (A) funkcja sprawdzajaca znajomosc jezyka u przewodnika 
CREATE OR REPLACE FUNCTION zna_ten_jezyk(integer,varchar) RETURNS boolean AS $zna_ten_jezyk$                      
DECLARE 
    V_liczba integer; 
BEGIN
    SELECT count(*) FROM przewodnicyjezyki WHERE id_przew = $1 AND nazwa_jez = $2 INTO V_liczba; 
    IF V_liczba > 0 THEN  
        RETURN TRUE; 
    END IF; 
    RETURN FALSE; 
END; 
$zna_ten_jezyk$ LANGUAGE plpgsql; 
 
-- (B) funkcja sprawdzajaca znajomosc obiektu u przewodnika 
CREATE OR REPLACE FUNCTION zna_ten_obiekt(integer,integer) RETURNS boolean AS $zna_ten_obiekt$                      
DECLARE 
    V_liczba integer; 
BEGIN
    SELECT count(*) FROM przewodnicyobiekty WHERE id_przew = $1 AND id_ob = $2 INTO V_liczba; 
    IF V_liczba > 0 THEN  
        RETURN TRUE; 
    END IF; 
    RETURN FALSE; 
END; 
$zna_ten_obiekt$ LANGUAGE plpgsql; 
 
-- (C) funkcja sprawdzajaca czy obiekt nie jest przeludniony w tym czasie 
CREATE OR REPLACE FUNCTION bez_nadmiaru(integer,date,time,time,integer) RETURNS boolean AS $bez_nadmiaru$                      
DECLARE 
    V_od time := normalizuj_czas($3); 
    V_do time := normalizuj_czas($4); 
    V_spr time := V_od; 
    v_os integer; 
    V_poj integer; 
BEGIN 
    SELECT pojemnosc FROM obiekty WHERE id_ob = $1 INTO V_poj; 
    LOOP 
        SELECT sum(il_miejsc) FROM wejscia WHERE id_ob = $1 AND data = $2 AND $3 <= V_spr AND $4 > V_spr INTO V_os; 
        IF V_os + $5 > V_poj THEN 
            RETURN FALSE; 
        END IF; 
        EXIT WHEN V_spr >= V_do; 
        V_spr := V_spr + interval '5 minutes'; 
    END LOOP; 
    RETURN TRUE; 
END; 
$bez_nadmiaru$ LANGUAGE plpgsql; 
 
-- (D) funkcja sprawdzajaca czy obiekt jest otwarty w tym czasie 
CREATE OR REPLACE FUNCTION obiekt_czynny(integer,date,time,time) RETURNS boolean AS $obiekt_czynny$                      
DECLARE 
    V_liczba integer; 
    V_dzien_tyg integer := extract(dow FROM $2); 
BEGIN 
    IF V_dzien_tyg = 0 THEN 
        V_dzien_tyg = 7; 
    END IF; 
    SELECT count(*) FROM okresy_otwarcia WHERE id_ob = $1 AND dzien_tyg = V_dzien_tyg AND godzina_od <= $3 AND godzina_do >= $4 INTO V_liczba; 
    IF V_liczba > 0 THEN 
        RETURN TRUE; 
    END IF; 
    RETURN FALSE; 
END; 
$obiekt_czynny$ LANGUAGE plpgsql; 
 
-- (E) relacja: 
CREATE TABLE wejscia ( 
    id_ob integer NOT NULL REFERENCES obiekty(id_ob), 
    id_przew integer REFERENCES przewodnicy(id_przew), 
    nazwa_jez varchar REFERENCES jezyki(nazwa_jez), 
    czas_od time NOT NULL, 
    czas_do time NOT NULL, 
    data date NOT NULL, 
    il_miejsc integer NOT NULL CHECK(il_miejsc > 0), 
    id_wej integer NOT NULL PRIMARY KEY, 
    CONSTRAINT godziny_chronologicznie CHECK(czas_od < czas_do), 
    CONSTRAINT przew_plus_jezyk_albo_nic CHECK((id_przew IS NULL AND nazwa_jez IS NULL) OR (id_przew IS NOT NULL AND nazwa_jez IS NOT NULL)),
    CONSTRAINT zna_ten_jezyk CHECK(id_przew IS NULL OR zna_ten_jezyk(id_przew,nazwa_jez)), 
    CONSTRAINT zna_ten_obiekt CHECK(id_przew IS NULL OR zna_ten_obiekt(id_przew,id_ob)), 
    CONSTRAINT bez_przepelnienia CHECK(bez_nadmiaru(id_ob,data,czas_od,czas_do,il_miejsc)), 
    CONSTRAINT obiekt_czynny  CHECK(obiekt_czynny(id_ob,data,czas_od,czas_do))
); 
 
-- (F) sekwencja dla id: 
CREATE SEQUENCE id_dla_wej START 1; 
 
-- (G) wyzwalacz do insert'a: 
CREATE OR REPLACE FUNCTION dodaj_wej() RETURNS trigger AS $dodaj_wej$                  
BEGIN          
    NEW.id_wej = nextval('id_dla_wej'); 
    RETURN NEW; 
END; 
$dodaj_wej$ LANGUAGE plpgsql; 
CREATE TRIGGER dodaj_wej BEFORE INSERT ON wejscia 
FOR EACH ROW EXECUTE PROCEDURE dodaj_wej(); 
 
-- (H) wyzwalacz do update'a: 
CREATE OR REPLACE FUNCTION modyf_wej() RETURNS trigger AS $modyf_wej$                  
DECLARE 
    V_biletow integer;
BEGIN 
    NEW.id_wej = OLD.id_wej; 
    SELECT count(*) FROM bilety WHERE id_wej = NEW.id_wej INTO V_biletow; 
    IF V_biletow > NEW.il_miejsc THEN
        NEW.il_miejsc = OLD.il_miejsc;
    END IF;
    IF NEW = OLD THEN 
        RETURN NULL; 
    END IF; 
    RETURN NEW; 
END; 
$modyf_wej$ LANGUAGE plpgsql; 
CREATE TRIGGER modyf_wej BEFORE UPDATE ON wejscia 
FOR EACH ROW EXECUTE PROCEDURE modyf_wej(); 
 
------------------------------------ 
-- 10. UZYTKOWNICY: [!!!] 
 
-- (A) relacja: 
CREATE TABLE uzytkownicy ( 
    login varchar NOT NULL CONSTRAINT login_nie_pust CHECK(login != '') PRIMARY KEY, 
    -- hash = md5(md5(password)+md5(password+salt)) 
    hash varchar(32) NOT NULL, 
    salt varchar(16) NOT NULL, 
    imie varchar NOT NULL CONSTRAINT imie_nie_pust CHECK(imie != ''), 
    nazwisko varchar NOT NULL CONSTRAINT nazwisko_nie_pust CHECK(nazwisko != ''), 
    mail varchar NOT NULL UNIQUE CONSTRAINT mail_nie_pust CHECK(mail != ''), 
    czy_admin boolean NOT NULL DEFAULT FALSE,
    czy_aktywny boolean NOT NULL DEFAULT TRUE
); 
 
------------------------------------ 
-- 11. OCENY: [OK] 
 
-- (A) relacja: 
CREATE TABLE oceny ( 
    id_wej integer NOT NULL REFERENCES wejscia(id_wej), 
    login varchar NOT NULL REFERENCES uzytkownicy(login), 
    ocena_ob integer CONSTRAINT ocena_ob_od_0_do_5 CHECK(ocena_ob BETWEEN 0 AND 5), 
    ocena_przew integer CONSTRAINT ocena_przew_od_0_do_5 CHECK(ocena_ob BETWEEN 0 AND 5), 
    komentarz text, 
    PRIMARY KEY(id_wej,login) 
); 
 
-- (B) wyzwalacz do inserta: 
CREATE OR REPLACE FUNCTION dodaj_ocene() RETURNS trigger AS $dodaj_ocene$ 
DECLARE 
    V_id_przew integer; 
BEGIN 
    SELECT id_przew FROM wejscia WHERE id_wej = NEW.id_wej INTO V_id_przew; 
    IF V_id_przew IS NULL THEN 
        NEW.ocena_przew = NULL; 
    END IF; 
    RETURN NEW; 
END; 
$dodaj_ocene$ LANGUAGE plpgsql; 
CREATE TRIGGER dodaj_ocene BEFORE INSERT ON oceny 
FOR EACH ROW EXECUTE PROCEDURE dodaj_ocene(); 
 
-- (C) regula do update'a blokujaca zmiany: 
CREATE RULE modyf_oceny AS ON UPDATE TO oceny 
DO INSTEAD NOTHING; 

-- (D) funkcja wyliczajaca ocene obiektu o podanym id
CREATE OR REPLACE FUNCTION ocena_ob(integer) RETURNS float AS $ocena_ob$ 
BEGIN
        RETURN (SELECT avg(ocena_ob) FROM oceny o JOIN bilety b USING(id_wej) JOIN wejscia w USING(id_wej) WHERE id_ob = $1);
END;
$ocena_ob$ LANGUAGE plpgsql;

-- (D) funkcja wyliczajaca ocene przewodnika o podanym id
CREATE OR REPLACE FUNCTION ocena_przew(integer) RETURNS float AS $ocena_przew$ 
BEGIN
        RETURN (SELECT avg(ocena_przew) FROM oceny o JOIN bilety b USING(id_wej) JOIN wejscia w USING(id_wej) WHERE id_przew = $1);
END;
$ocena_przew$ LANGUAGE plpgsql;
 
------------------------------------ 
-- 12. TYPY_BILETOW: [OK] 
 
-- (A) relacja: 
CREATE TABLE typy_biletow ( 
    id_ob integer NOT NULL REFERENCES obiekty(id_ob), 
    nazwa_typu varchar NOT NULL CONSTRAINT nazwa_typu_nie_pust CHECK(nazwa_typu != ''), 
    cena numeric(6,2) NOT NULL CONSTRAINT cena_nieujemna CHECK(cena >= 0),
    czy_przew boolean NOT NULL,
    id_typu integer PRIMARY KEY,
    UNIQUE(id_ob,nazwa_typu)
); 

-- (B) sekwencja dla id: 
CREATE SEQUENCE id_dla_typu START 1; 
 
-- (C) wyzwalacz do insert'a: 
CREATE OR REPLACE FUNCTION dodaj_typ() RETURNS trigger AS $dodaj_typ$                  
BEGIN          
    NEW.id_typu = nextval('id_dla_typu'); 
    RETURN NEW; 
END;
$dodaj_typ$ LANGUAGE plpgsql; 
CREATE TRIGGER dodaj_typ BEFORE INSERT ON typy_biletow 
FOR EACH ROW EXECUTE PROCEDURE dodaj_typ(); 

-- (D) regula do update'a blokujaca zmiany: 
CREATE RULE modyf_typu AS ON UPDATE TO typy_biletow 
DO INSTEAD NOTHING; 

------------------------------ 
-- 13. BILETY: [OK] 
 
 -- (A) funkcja sprawdzajaca, czy dany rodzaj biletu moze zostac wykorzystany na dane wejscie
 CREATE OR REPLACE FUNCTION bilet_jest_odpowiedni(integer,integer) RETURNS boolean AS $bilet_jest_odpowiedni$                      
DECLARE 
    V_id_ob1 integer;
    V_id_ob2 integer;
    V_id_przew integer;
    V_przew boolean;
BEGIN
    SELECT id_ob FROM wejscia WHERE id_wej = $2 INTO V_id_ob1;
    SELECT id_ob FROM typy_biletow WHERE id_typu = $1 INTO V_id_ob2;
    SELECT id_przew FROM wejscia WHERE id_wej = $2 INTO V_id_przew;
    SELECT czy_przew FROM typy_biletow WHERE id_typu = $1 INTO V_przew;
    IF V_id_ob1 = V_id_ob2 AND ((V_id_przew IS NULL AND V_przew = FALSE) OR (V_id_przew IS NOT NULL AND V_przew = TRUE)) THEN  
        RETURN TRUE; 
    END IF; 
    RETURN FALSE; 
END; 
$bilet_jest_odpowiedni$ LANGUAGE plpgsql; 

 -- (B) funkcja zwracajaca ilosc wolnych miejsc na wejscie o podanym id
 CREATE OR REPLACE FUNCTION il_wolnych_miejsc(integer) RETURNS integer AS $ile_wolnych_miejsc$                      
DECLARE
    V_miejsc integer; 
    V_biletow integer; 
BEGIN
    SELECT il_miejsc FROM wejscia WHERE id_wej = $1 INTO V_miejsc;
    SELECT count(*) FROM bilety WHERE id_wej = $1 INTO V_biletow;
    RETURN (V_miejsc - V_biletow); 
END; 
$ile_wolnych_miejsc$ LANGUAGE plpgsql; 
 
-- (C) relacja: 
CREATE TABLE bilety ( 
    id_wej integer NOT NULL REFERENCES wejscia(id_wej), 
    id_typu integer NOT NULL REFERENCES typy_biletow(id_typu), 
    login varchar NOT NULL REFERENCES uzytkownicy(login), 
    data_rezerwacji timestamp NOT NULL, 
    id_bil integer NOT NULL PRIMARY KEY,
    CONSTRAINT bilet_jest_odpowiedni CHECK(bilet_jest_odpowiedni(id_typu, id_wej)),
    CONSTRAINT sa_wolne_miejsca CHECK(il_wolnych_miejsc(id_wej) > 0)
); 
 
-- (D) sekwencja dla id: 
CREATE SEQUENCE id_dla_bil START 1; 
 
-- (E) wyzwalacz do insert'a: 
CREATE OR REPLACE FUNCTION dodaj_bil() RETURNS trigger AS $dodaj_bil$                  
BEGIN          
    NEW.id_bil = nextval('id_dla_bil');
    RETURN NEW; 
END; 
$dodaj_bil$ LANGUAGE plpgsql; 
CREATE TRIGGER dodaj_bil BEFORE INSERT ON bilety 
FOR EACH ROW EXECUTE PROCEDURE dodaj_bil(); 
 
-- (F) regula do update'a blokujaca zmiany: 
CREATE RULE modyf_bil AS ON UPDATE TO bilety 
DO INSTEAD NOTHING;

-- (G) funkcja pozwalajaca kupic bilet na wejscie indywidualne
CREATE OR REPLACE FUNCTION kup_bil_ind(integer, time, time, date, integer, integer, varchar, timestamp) RETURNS boolean AS $kup_bil_ind$                  
DECLARE
    V_wej integer;
    V_data timestamp;
BEGIN
        BEGIN
    IF V_data IS NULL THEN
        V_data := now();
    END IF;
    SELECT id_wej FROM wejscia WHERE id_ob = $1 AND czas_od = $2 AND czas_do = $3 AND data = $4 INTO V_wej;
    IF V_wej IS NULL THEN
        INSERT INTO wejscia VALUES($1,NULL,NULL,$2,$3,$4,$6);
        SELECT id_wej FROM wejscia WHERE id_ob = $1 AND czas_od = $2 AND czas_do = $3 AND data = $4 INTO V_wej;
    ELSE
        UPDATE wejscia SET il_miejsc = il_miejsc + $6 WHERE id_wej = V_wej;
    END IF;
    FOR i IN 1..$6 LOOP
            INSERT INTO bilety VALUES(V_wej,$5,$7,V_data);
    END LOOP;
            EXCEPTION
                WHEN others THEN
                        RETURN FALSE;
    END;
    RETURN TRUE;
END; 
$kup_bil_ind$ LANGUAGE plpgsql;  
 
------------------------------------ 
 
COMMIT;